﻿using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using SD.Database.Classes;
using System.Collections;
using System.Collections.Generic;
using DBAccess;

//If planet is empty && fleets contains cs: check culture maybe colonize
//If planet is empty set fleet
//If planet is unknown initiate attack procedure, use transports & cs if win
//If planet is the same player set fleet and use cs
//if planet is enemy initiate attack proc, use transports & cs if win
namespace SD.Database
{
    public partial class StoredProcedures
    {
        struct Fleet
        {
            public TimeSpan Span;
            public int Id;
            public int Owner;
            public int SId;
            public int PId;
            public int CS;
            public int TR;
            public int DS;
            public int CR;
            public int BS;
        }

        public static void UpdateFleets()
        {
            int intervalTime, pp;
            double AttackBonus, DefBonus;
            try
            {
                intervalTime = int.Parse(Configuration.GetConfigurationForOption("SmallUpdateInterval"));//in seconds
                AttackBonus = double.Parse(Configuration.GetConfigurationForOption("AttackBonus"));
            }
            catch (Exception ex)
            {
                throw new Exception("SmallUpdateInterval", ex);
            }
            try
            {
                pp = int.Parse(Configuration.GetConfigurationForOption("PPpointsFromCS"));
                DefBonus = double.Parse(Configuration.GetConfigurationForOption("AttackBonus"));
            }
            catch (Exception ex)
            {
                throw new Exception("PPpointsFromCS", ex);
            }
            List<Fleet> fleets = new List<Fleet>();
            DataSet datas = DAL.GetInstance().GetData("Select * from fleets");

            if (datas.Tables.Count == 0) return;

            foreach (DataRow rdr in datas.Tables[0].Rows)
            {
                DateTime dt = DateTime.Parse(rdr[11].ToString());
                TimeSpan s = dt - DateTime.Now;
                int fid = int.Parse(rdr[0].ToString());
                int owner = int.Parse(rdr["OwnerID"].ToString());
                int sId = int.Parse(rdr["ToSystem"].ToString());
                int pId = int.Parse(rdr["ToPlanet"].ToString());
                int cs = int.Parse(rdr["ColonyShips"].ToString());
                int tr = int.Parse(rdr["Transports"].ToString());
                int ds = int.Parse(rdr["Destroyers"].ToString());
                int cr = int.Parse(rdr["Crusiers"].ToString());
                int bs = int.Parse(rdr["Battleships"].ToString());
                fleets.Add(new Fleet { Span = s, Id = fid, Owner = owner, SId = sId, PId = pId, CS = cs, TR = tr, DS = ds, CR = cr, BS = bs });
            }

            foreach (Fleet a in fleets)
            {
                ProcessFleet(a, intervalTime, AttackBonus, DefBonus, pp);
            }
        }

        private static void ProcessFleet(Fleet a, int intervalTime, double AttackBonus, double DefBonus, int pp)
        {
            TimeSpan s = a.Span;
            int fid = a.Id;
            int owner = a.Owner;
            int sId = a.SId;
            int pId = a.PId;
            int cs = a.CS;
            int tr = a.TR;
            int ds = a.DS;
            int cr = a.CR;
            int bs = a.BS;
            // InsertNews(8, DateTime.Now, "Ts: " + sId.ToString() + " PS:" + pId.ToString() + " " + s.TotalSeconds.ToString());
            if (s.TotalSeconds < intervalTime)
            {
                int FleetOwner = UserFunctions.FleetOwner(sId, pId);

                if (FleetOwner != owner && FleetOwner >= 1)//battle always come first
                {
                    int AttackerAt, DefenderAt, AttackerDef, DefenderDef;
                    int DefID = UserFunctions.FleetOwner(sId, pId);
                    AttackerAt = UserFunctions.GetPlayerInt(owner, "Attack");
                    DefenderAt = UserFunctions.GetPlayerInt(DefID, "Attack");
                    AttackerDef = UserFunctions.GetPlayerInt(owner, "Defense");
                    DefenderDef = UserFunctions.GetPlayerInt(DefID, "Defense");

                    int AttackerPhy = (int)UserFunctions.GetPlayerFloat(owner, "Physics");
                    int AttackerMath = (int)UserFunctions.GetPlayerFloat(owner, "Math");
                    int DefenderPhy = (int)UserFunctions.GetPlayerFloat(DefID, "Physics");
                    int DefenderMath = (int)UserFunctions.GetPlayerFloat(DefID, "Math");

                    //get bonuses from artifacts
                    if (UserFunctions.UsedArtifact(owner) != null)
                    {
                        switch (UserFunctions.UsedArtifact(owner))
                        {
                            case "PG": AttackerPhy += 7; break;
                            case "GG": AttackerPhy += 14; break;
                            case "ES": AttackerMath += 08; break;
                            case "PS": AttackerMath += 16; break;
                            case "AF": AttackerPhy += 15; AttackerMath += 15; break;
                        }
                    }
                    if (UserFunctions.UsedArtifact(DefID) != null)
                    {
                        switch (UserFunctions.UsedArtifact(DefID))
                        {
                            case "PG": DefenderPhy += 7; break;
                            case "GG": DefenderPhy += 14; break;
                            case "ES": DefenderMath += 8; break;
                            case "PS": DefenderMath += 16; break;
                            case "AF": DefenderPhy += 15; DefenderMath += 15; break;
                        }
                    }
                    Dictionary<string, int> fleetOnPlanet = Planets.FleetOnPlanet(sId, pId);
                    int defDs = fleetOnPlanet["Destroyers"];
                    int defCr = fleetOnPlanet["Crusiers"];
                    int defBs = fleetOnPlanet["Battleships"];
                    double defSb = fleetOnPlanet["Starbase"];
                    if (defDs + defCr + defBs + defSb > 0)//in case there is no fleet on planet do not start fight
                    {
                        //and if win attack transports
                        int attCv, defCV; double attchance, winninglosses;
                        bool win = Equations.AttackProcedure(AttackerAt, AttackerDef, AttackerPhy, AttackerMath, ref ds, ref cr, ref bs,
                            DefenderAt, DefenderDef, DefenderPhy, DefenderMath, ref defDs, ref defCr, ref defBs, ref defSb, out attCv, out defCV, out attchance, out winninglosses);
                        InsertLog(DateTime.Now, "Update fleets", "s:" + sId.ToString() + " p:" + pId.ToString() + " aCV:" + attCv.ToString() + " dCV:" + defCV.ToString() + " winner:" + win.ToString() + " loses:" + winninglosses.ToString());
                        if (win == true)
                        {

                            InsertNews(owner, DateTime.Now, "Congratulations! You have won battle on the orbit of: " + Systems.SystemName(sId) + " #" + pId.ToString() + " against " + UserFunctions.PlayerName(DefID).ToString() + ".<br />\n" + "You gained " + defCV.ToString() + " experience.<br/>\n" +
                                "You lost about " + ((int)(winninglosses * 100)).ToString() + "% of your fleet.");
                            InsertNews(DefID, DateTime.Now, "Your fleet was defeated on the orbit of: " + Systems.SystemName(sId) + " #" + pId.ToString() + " against " + UserFunctions.PlayerName(owner).ToString() + ".<br/>" +
                                "You killed about " + ((int)(winninglosses * 100)).ToString() + "% of enemy fleet.");
                            InsertBattle(owner, attCv, DefID, defCV, DateTime.Now, sId, pId, owner);
                            //set empty planet fleet
                            SetFleetWithCS(sId, pId, 0, 0, 0, 0, 0, 0);
                            SetSbOnPlanet(sId, pId, 0);
                            SetExperience(owner, defCV);
                            FleetOwner = 0;
                        }
                        else
                        {
                            InsertNews(DefID, DateTime.Now, "Congratulations! Your defending forces have won battle on the orbit of: " + Systems.SystemName(sId) + " #" + pId.ToString() + " against " + UserFunctions.PlayerName(owner).ToString() + ".<br />\n" + "You gained " + attCv.ToString() + " experience.<br/>" +
                                "You lost about " + ((int)(winninglosses * 100)).ToString() + "% of your fleet.");
                            InsertNews(owner, DateTime.Now, "Your fleet was defeated on the orbit of: " + Systems.SystemName(sId) + " #" + pId.ToString() + " against " + UserFunctions.PlayerName(DefID).ToString() + ".<br/>" +
                                "You killed about " + ((int)(winninglosses * 100)).ToString() + "% of enemy fleet.");
                            InsertBattle(owner, attCv, DefID, defCV, DateTime.Now, sId, pId, DefID);
                            SetFleetWithCS(sId, pId, DefID, fleetOnPlanet["ColonyShips"], fleetOnPlanet["Transports"], defDs, defCr, defBs);
                            SetSbOnPlanet(sId, pId, defSb);
                            SetExperience(DefID, attCv);
                            FleetsFunctions.RemoveFleet(fid);
                            return;
                        }
                    }
                }

                bool CS = (cs != 0 ? true : false);
                bool TR = (tr != 0 ? true : false);
                bool UnknownPlanet = Planets.IsUnknown(sId, pId);
                bool EnemyPlanet = (Planets.PlanetOwner(sId, pId) != owner ? true : false);
                bool EmptyPlanet = Planets.IsEmptyPlanet(sId, pId);
                bool FleetExists = FleetsFunctions.FleetExists(sId, pId);
                bool CanColonize = (UserFunctions.PlayerPlanets(owner) < UserFunctions.PlayerCulture(owner));
                bool SamePlayer = (Planets.PlanetOwner(sId, pId) == owner);
                if (EmptyPlanet == true)
                {
                    if (CanColonize == true && CS == true)
                    {
                        Planets.ColonizePlanet(sId, pId, owner);
                        AddFleet(sId, pId, owner, tr, ds, cr, bs);
                        Planets.AddProductionPoints(sId, pId, (cs - 1) * pp);
                    }
                    else
                    {
                        //if there is some fleet we should add it not delete
                        AddFleetWithCS(sId, pId, owner, cs, tr, ds, cr, bs);
                    }
                }
                else if (SamePlayer == true)
                {
                    AddFleet(sId, pId, owner, tr, ds, cr, bs);
                    Planets.AddProductionPoints(sId, pId, cs * pp);
                }
                else if (UnknownPlanet == true || EnemyPlanet == true)
                {
                    UseTransports(sId, pId, owner, cs, tr, ds, cr, bs);
                    //if (CanColonize == true && TR == true)
                    //{
                    //    UseTransports(sId, pId, owner, cs, tr, ds, cr, bs);
                    //}
                    //else
                    //    SetFleetWithCS(sId, pId, owner, cs, tr, ds, cr, bs);
                }


                //remove fleet
                FleetsFunctions.RemoveFleet(fid);
            }
        }

        private static void SetSbOnPlanet(int sId, int pId, double defSb)
        {
            DAL.GetInstance().UpdateData("Update Planets SET Starbase =  @param0 Where SystemID = @param1 and PlanetID = @param2", new List<object>() { defSb, sId, pId });
        }
        //If we come to this moment planet should be empty so just add fleet
        private static void UseTransports(int sId, int pId, int owner, int cs, int tr, int ds, int cr, int bs)
        {
            int pp = int.Parse(Configuration.GetConfigurationForOption("PPpointsFromCS"));
            if (Planets.IsEmptyPlanet(sId, pId) == false)
            {
                if (UserFunctions.PlayerPlanets(owner) < UserFunctions.PlayerCulture(owner))
                {
                    //conquer the planet
                    int pop = Planets.PopulationOnPlanet(sId, pId);
                    if (pop <= tr)
                    {
                        Planets.ConquerPlanet(sId, pId, owner);
                        Planets.AddProductionPoints(sId, pId, cs * pp);
                        AddFleetWithCS(sId, pId, owner, 0, tr - pop, ds, cr, bs);
                    }
                }
                else
                {
                    //destroy pop
                    Planets.KillPopOnPlanet(sId, pId, owner, ref tr);
                    AddFleetWithCS(sId, pId, owner, cs, tr, ds, cr, bs);
                }
            }
            else
            {
                AddFleetWithCS(sId, pId, owner, cs, tr, ds, cr, bs);
            }
        }


        public static void AddFleetWithCS(int sid, int pid, int OwnerID, int cs, int tr, int ds, int cr, int bs)
        {
            InsertLog(DateTime.Now, "AddFleetWithCS", "Add fleet with cs: sId: " + sid.ToString() + ", pID:" + pid.ToString() + " o:" + OwnerID.ToString());
            DAL.GetInstance().UpdateData("Update Planets SET ColonyShips = ColonyShips + @param0, Transports = Transports + @param1, Destroyers = Destroyers + @param2,Crusiers = Crusiers + @param3, Battleships = Battleships + @param4, FleetOwnerID = @param5 Where SystemID = @param6 and PlanetID = @param7",
                new List<object>() { cs, tr, ds, cr, bs, OwnerID, sid, pid });
        }
        public static void SetFleetWithCS(int sid, int pid, int OwnerID, int cs, int tr, int ds, int cr, int bs)
        {
            InsertLog(DateTime.Now, "SetFleetWithCS", "Set fleet with cs: sId: " + sid.ToString() + ", pID:" + pid.ToString() + " o:" + OwnerID.ToString());
            DAL.GetInstance().UpdateData("Update Planets SET ColonyShips = @param0, Transports =  @param1, Destroyers = @param2,Crusiers =  @param3, Battleships = @param4, FleetOwnerID = @param5 Where SystemID = @param6 and PlanetID = @param7",
                new List<object>() { cs, tr, ds, cr, bs, OwnerID, sid, pid });
        }

        public static void AddFleet(int sid, int pid, int OwnerId, int tr, int ds, int cr, int bs)
        {
            InsertLog(DateTime.Now, "AddFleet", "Add fleet with cs: sId: " + sid.ToString() + ", pID:" + pid.ToString() + " o:" + OwnerId.ToString());
            DAL.GetInstance().UpdateData("Update Planets SET  Transports = Transports + @param1, Destroyers = Destroyers + @param2,Crusiers = Crusiers + @param3, Battleships = Battleships + @param4, FleetOwnerID = @param5 Where SystemID = @param6 and PlanetID = @param7",
                  new List<object>() { 0, tr, ds, cr, bs, OwnerId, sid, pid });
        }
    };
}